#include "video.h"

VideoDecoder::VideoDecoder() {
  pictureBgr = av_frame_alloc();
  pictureYuv = av_frame_alloc();
}

VideoDecoder::~VideoDecoder() {
  if (pictureBgr)
    free(pictureBgr);
  if (pictureYuv)
    free(pictureYuv);
  if (swsContext)
    sws_freeContext(swsContext);
  if (swsContextYuv)
    sws_freeContext(swsContextYuv);
  if (bufferForPictureBgr)
    delete[] bufferForPictureBgr;
  if (bufferForPictureYuv)
    delete[] bufferForPictureYuv;
  if (bgrData)
    delete[] bgrData;
  if (yuvData)
    delete[] yuvData;
}

void VideoDecoder::Scale2bgr(uint32_t width, uint32_t height, AVPixelFormat format,  AVFrame *frame) {
  if (prevWidth != width) {
    prevWidth = width;
    swsContext = sws_getCachedContext(swsContext, width, height, format, scaleWidth, scaleHeight,
                                      AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
  }
  sws_scale(swsContext, (const uint8_t* const*)frame->data, frame->linesize,
            0, height, pictureBgr->data, pictureBgr->linesize);
  memcpy(bgrData, pictureBgr->data[0], 3 * scaleHeight * scaleWidth);
}

void VideoDecoder::ScaleYuv(uint32_t width, uint32_t height, AVPixelFormat format, AVFrame *frame) {
  if (yuvPrevWidth != width) {
    prevWidth = width;
    swsContextYuv = sws_getCachedContext(swsContextYuv, width, height, format, scaleWidth, scaleHeight,
                                      AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
  }
  sws_scale(swsContextYuv, (const uint8_t* const*)frame->data, frame->linesize,
            0, height, pictureYuv->data, pictureYuv->linesize);

  uint32_t h = scaleHeight;
  uint32_t w = scaleWidth;
  int u = w*h;
  int v = w*h*5/4;
  for(int i=0;i<h;i++)
    memcpy(&yuvData[i*w],&pictureYuv->data[0][i*pictureYuv->linesize[0]],w);

  for(int i=0;i<h/2;i++)
  {
    memcpy(&yuvData[i*w/2+u],&pictureYuv->data[1][i*pictureYuv->linesize[1]],w/2);
    memcpy(&yuvData[i*w/2+v],&pictureYuv->data[2][i*pictureYuv->linesize[2]],w/2);
  }
}

void VideoDecoder::SetScale(uint32_t width, uint32_t height) {
  scaleWidth = width;
  scaleHeight = height;
  bufferForPictureBgr = new uint8_t[av_image_get_buffer_size(AV_PIX_FMT_BGR24, width, height, 1)];
  bufferForPictureYuv = new uint8_t[av_image_get_buffer_size(AV_PIX_FMT_YUV420P, width, height, 1)];
  bgrData = new uint8_t[av_image_get_buffer_size(AV_PIX_FMT_BGR24, width, height, 1)];
  yuvData = new uint8_t[av_image_get_buffer_size(AV_PIX_FMT_YUV420P, width, height, 1)];
  av_image_fill_arrays(pictureBgr->data, pictureBgr->linesize, bufferForPictureBgr, AV_PIX_FMT_BGR24,width,height,1);
  av_image_fill_arrays(pictureYuv->data, pictureYuv->linesize, bufferForPictureYuv, AV_PIX_FMT_YUV420P,width,height,1);
}

